package com.why;


import com.why.basictype.U1;
import com.why.basictype.U2;
import com.why.basictype.U4;
import com.why.constantpool.*;

import java.io.InputStream;
import java.util.ArrayList;

/**
 * @author by xiaoTian
 * @date 2022/5/21.
 */
public class ClassReader {
    public static void analyze(InputStream inputStream){
        ClassFile classFile = new ClassFile();
        classFile.magic = U4.read(inputStream);
        classFile.minorVersion = U2.read(inputStream);
        classFile.majorVersion = U2.read(inputStream);
        classFile.constantPoolCount = U2.read(inputStream);
        ConstantPool constantPool = readConstantPool(inputStream,(short) (classFile.constantPoolCount.getValue() - 1));
        classFile.constantPoolInfos = constantPool.getConstantPoolInfo();
        classFile.accessFlags = U2.read(inputStream);
        classFile.thisClass = U2.read(inputStream);
        classFile.superClass = U2.read(inputStream);
        classFile.interfaceCount = U2.read(inputStream);
        classFile.interfaces = new U2[classFile.interfaceCount.getValue()];
        readInterfaces(inputStream,classFile);
        classFile.fieldCount = U2.read(inputStream);
        readField(inputStream,constantPool,classFile);






        print(classFile);
    }

    private static void readField(InputStream inputStream, ConstantPool constantPool, ClassFile classFile) {
        ArrayList<FieldInfo> list = new ArrayList<>();
        for (int i = 0; i < classFile.fieldCount.getValue(); i++) {
            FieldInfo fieldInfo = new FieldInfo(constantPool);
        }
    }

    private static void readInterfaces(InputStream inputStream, ClassFile classFile) {
        for (int i = 0; i < classFile.interfaceCount.getValue(); i++) {
            classFile.interfaces[i] = U2.read(inputStream);
        }
    }


    public static void print(ClassFile file){
        System.out.println(file.toString());;
    }



    public static ConstantPool readConstantPool(InputStream inputStream, short constantPoolCount){
        ConstantPool constantPool = new ConstantPool();
        ArrayList<ConstantPoolInfo> infoList = new ArrayList<>();
        for (short i = 0; i < constantPoolCount; i++) {
            U1 tag = U1.read(inputStream);
            // 找到常量池对应的类型
//            System.out.println(tag.getValue());
            ConstantPoolInfo constantPoolInfo = newConstantPool(inputStream,tag.getValue());
            infoList.add(constantPoolInfo);
            // 如果是U8类型的，需要增加一个计数器
            if (tag.getValue() == ConstantPoolInfo.CONSTANT_LONG_INFO ||
                    tag.getValue() == ConstantPoolInfo.CONSTANT_DOUBLE_INFO) {
                i++;
                infoList.add(null);
            }
        }
        constantPool.setConstantPoolInfos(infoList.toArray(new ConstantPoolInfo[0]));
        return constantPool;
    }

    private static ConstantPoolInfo newConstantPool(InputStream inputStream, byte tag) {
        ConstantPoolInfo constantPoolInfo = null;
        switch (tag){
            case ConstantPoolInfo.CONSTANT_UTF8_INFO:
                constantPoolInfo = new ConstantUtf8Info(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_METHODREF_INFO:
                constantPoolInfo = new ConstantMethodRefInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_CLASS_INFO:
                constantPoolInfo = new ConstantClassInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_DOUBLE_INFO:
                constantPoolInfo = new ConstantDoubleInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_FIELDREF_INFO:
                constantPoolInfo = new ConstantFieldRefInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_FLOAT_INFO:
                constantPoolInfo = new ConstantFloatRefInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_INTEGER_INFO:
                constantPoolInfo = new ConstantIntegerInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_INTERFACEMETHODREF_INFO:
                constantPoolInfo = new ConstantInterfaceMethodRefInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_INVOKEDYNAMIC_INFO:
                constantPoolInfo = new ConstantInvokeDynamicInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_LONG_INFO:
                constantPoolInfo = new ConstantLongInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_METHODHANDLE_INFO:
                constantPoolInfo = new ConstantMethodHandleInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_NAMEANDTYPE_INFO:
                constantPoolInfo = new ConstantNameAndTypeInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_STRING_INFO:
                constantPoolInfo = new ConstantStringInfo(tag);constantPoolInfo.read(inputStream);
                break;
            case ConstantPoolInfo.CONSTANT_METHODTYPE_INFO:
                constantPoolInfo = new ConstantMethodTypeInfo(tag);constantPoolInfo.read(inputStream);
                break;
        }
//        assert constantPoolInfo != null;
//        constantPoolInfo.read(inputStream);
        return constantPoolInfo;


    }

}